// Copyright 2010-2025 Google LLC
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Classes to represent sparse vectors.
//
// The following are very good references for terminology, data structures,
// and algorithms:
//
// I.S. Duff, A.M. Erisman and J.K. Reid, "Direct Methods for Sparse Matrices",
// Clarendon, Oxford, UK, 1987, ISBN 0-19-853421-3,
// http://www.amazon.com/dp/0198534213.
//
//
// T.A. Davis, "Direct methods for Sparse Linear Systems", SIAM, Philadelphia,
// 2006, ISBN-13: 978-0-898716-13, http://www.amazon.com/dp/0898716136.
//
//
// Both books also contain a wealth of references.

#ifndef OR_TOOLS_LP_DATA_SPARSE_VECTOR_H_
#define OR_TOOLS_LP_DATA_SPARSE_VECTOR_H_

#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <string>
#include <utility>

#include "absl/strings/str_format.h"
#include "ortools/base/logging.h"  // for CHECK*
#include "ortools/base/types.h"
#include "ortools/graph/iterators.h"
#include "ortools/lp_data/lp_types.h"
#include "ortools/lp_data/permutation.h"
#include "ortools/util/return_macros.h"

namespace operations_research {
namespace glop {

template <typename IndexType>
class SparseVectorEntry;

// --------------------------------------------------------
// SparseVector
// --------------------------------------------------------
// This class allows to store a vector taking advantage of its sparsity.
// Space complexity is in O(num_entries).
// In the current implementation, entries are stored in a first-in order (order
// of SetCoefficient() calls) when they are added; then the "cleaning" process
// sorts them by index (and duplicates are removed: the last entry takes
// precedence).
// Many methods assume that the entries are sorted by index and without
// duplicates, and DCHECK() that.
//
// Default copy construction is fully supported.
//
// This class uses strong integer types (i.e. no implicit cast to/from other
// integer types) for both:
// - the index of entries (eg. SparseVector<RowIndex> is a SparseColumn,
//   see ./sparse_column.h).
// - the *internal* indices of entries in the internal storage, which is an
//   entirely different type: EntryType.
// This class can be extended with a custom iterator/entry type for the
// iterator-based API. This can be used to extend the interface with additional
// methods for the entries returned by the iterators; for an example of such
// extension, see SparseColumnEntry in sparse_column.h. The custom entries and
// iterators should be derived from SparseVectorEntry and SparseVectorIterator,
// or at least provide the same public and protected interface.
//
// TODO(user): un-expose this type to client; by getting rid of the
// index-based APIs and leveraging iterator-based APIs; if possible.
template <typename IndexType,
          typename IteratorType = VectorIterator<SparseVectorEntry<IndexType>>>
class SparseVector {
 public:
  typedef IndexType Index;

  typedef StrictITIVector<Index, Fractional> DenseVector;
  typedef Permutation<Index> IndexPermutation;

  using Iterator = IteratorType;
  using Entry = typename Iterator::Entry;

  SparseVector();

  // NOTE(user): STL uses the expensive copy constructor when relocating
  // elements of a vector, unless the move constructor exists *and* it is marked
  // as noexcept. However, the noexcept annotation is banned by the style guide,
  // and the only way to get it is by using the default move constructor and
  // assignment operator generated by the compiler.
  SparseVector(const SparseVector& other);
#if !defined(_MSC_VER)
  SparseVector(SparseVector&& other) = default;
#endif

  SparseVector& operator=(const SparseVector& other);
#if !defined(_MSC_VER)
  SparseVector& operator=(SparseVector&& other) = default;
#endif

  // Read-only API for a given SparseVector entry. The typical way for a
  // client to use this is to use the natural range iteration defined by the
  // Iterator class below:
  //   SparseVector<int> v;
  //   ...
  //   for (const SparseVector<int>::Entry e : v) {
  //     LOG(INFO) << "Index: " << e.index() << ", Coeff: " << e.coefficient();
  //   }
  //
  // Note that this can only be used when the vector has no duplicates.
  //
  // Note(user): using either "const SparseVector<int>::Entry&" or
  // "const SparseVector<int>::Entry" yields the exact same performance on the
  // netlib, thus we recommend to use the latter version, for consistency.
  Iterator begin() const;
  Iterator end() const;

  // Clears the vector, i.e. removes all entries.
  void Clear();

  // Clears the vector and releases the memory it uses.
  void ClearAndRelease();

  // Reserve the underlying storage for the given number of entries.
  void Reserve(EntryIndex new_capacity);

  // Returns true if the vector is empty.
  bool IsEmpty() const;

  // Cleans the vector, i.e. removes zero-values entries, removes duplicates
  // entries and sorts remaining entries in increasing index order.
  // Runs in O(num_entries * log(num_entries)).
  void CleanUp();

  // Returns true if the entries of this SparseVector are in strictly increasing
  // index order and if the vector contains no duplicates nor zero coefficients.
  // Runs in O(num_entries). It is not const because it modifies
  // possibly_contains_duplicates_.
  bool IsCleanedUp() const;

  // Swaps the content of this sparse vector with the one passed as argument.
  // Works in O(1).
  void Swap(SparseVector* other);

  // Populates the current vector from sparse_vector.
  // Runs in O(num_entries).
  void PopulateFromSparseVector(const SparseVector& sparse_vector);

  // Populates the current vector from dense_vector.
  // Runs in O(num_indices_in_dense_vector).
  void PopulateFromDenseVector(const DenseVector& dense_vector);

  // Appends all entries from sparse_vector to the current vector; the indices
  // of the appended entries are increased by offset. If the current vector
  // already has a value at an index changed by this method, this value is
  // overwritten with the value from sparse_vector.
  // Note that while offset may be negative itself, the indices of all entries
  // after applying the offset must be non-negative.
  void AppendEntriesWithOffset(const SparseVector& sparse_vector, Index offset);

  // Returns true when the vector contains no duplicates. Runs in
  // O(max_index + num_entries), max_index being the largest index in entry.
  // This method allocates (and deletes) a Boolean array of size max_index.
  // Note that we use a mutable Boolean to make subsequent call runs in O(1).
  bool CheckNoDuplicates() const;

  // Same as CheckNoDuplicates() except it uses a reusable boolean vector
  // to make the code more efficient. Runs in O(num_entries).
  // Note that boolean_vector should be initialized to false before calling this
  // method; It will remain equal to false after calls to CheckNoDuplicates().
  // Note that we use a mutable Boolean to make subsequent call runs in O(1).
  bool CheckNoDuplicates(StrictITIVector<Index, bool>* boolean_vector) const;

  // Defines the coefficient at index, i.e. vector[index] = value;
  void SetCoefficient(Index index, Fractional value);

  // Removes an entry from the vector if present. The order of the other entries
  // is preserved. Runs in O(num_entries).
  void DeleteEntry(Index index);

  // Sets to 0.0 (i.e. remove) all entries whose fabs() is lower or equal to
  // the given threshold.
  void RemoveNearZeroEntries(Fractional threshold);

  // Same as RemoveNearZeroEntries, but the entry magnitude of each row is
  // multiplied by weights[row] before being compared with threshold.
  void RemoveNearZeroEntriesWithWeights(Fractional threshold,
                                        const DenseVector& weights);

  // Moves the entry with given Index to the first position in the vector. If
  // the entry is not present, nothing happens.
  void MoveEntryToFirstPosition(Index index);

  // Moves the entry with given Index to the last position in the vector. If
  // the entry is not present, nothing happens.
  void MoveEntryToLastPosition(Index index);

  // Multiplies all entries by factor.
  // i.e. entry.coefficient *= factor.
  void MultiplyByConstant(Fractional factor);

  // Multiplies all entries by its corresponding factor,
  // i.e. entry.coefficient *= factors[entry.index].
  void ComponentWiseMultiply(const DenseVector& factors);

  // Divides all entries by factor.
  // i.e. entry.coefficient /= factor.
  void DivideByConstant(Fractional factor);

  // Divides all entries by its corresponding factor,
  // i.e. entry.coefficient /= factors[entry.index].
  void ComponentWiseDivide(const DenseVector& factors);

  // Populates a dense vector from the sparse vector.
  // Runs in O(num_indices) as the dense vector values have to be reset to 0.0.
  void CopyToDenseVector(Index num_indices, DenseVector* dense_vector) const;

  // Populates a dense vector from the permuted sparse vector.
  // Runs in O(num_indices) as the dense vector values have to be reset to 0.0.
  void PermutedCopyToDenseVector(const IndexPermutation& index_perm,
                                 Index num_indices,
                                 DenseVector* dense_vector) const;

  // Performs the operation dense_vector += multiplier * this.
  // This is known as multiply-accumulate or (fused) multiply-add.
  void AddMultipleToDenseVector(Fractional multiplier,
                                DenseVector* dense_vector) const;

  // WARNING: BOTH vectors (the current and the destination) MUST be "clean",
  // i.e. sorted and without duplicates.
  // Performs the operation accumulator_vector += multiplier * this, removing
  // a given index which must be in both vectors, and pruning new entries whose
  // absolute value are under the given drop_tolerance.
  void AddMultipleToSparseVectorAndDeleteCommonIndex(
      Fractional multiplier, Index removed_common_index,
      Fractional drop_tolerance, SparseVector* accumulator_vector) const;

  // Same as AddMultipleToSparseVectorAndDeleteCommonIndex() but instead of
  // deleting the common index, leave it unchanged.
  void AddMultipleToSparseVectorAndIgnoreCommonIndex(
      Fractional multiplier, Index removed_common_index,
      Fractional drop_tolerance, SparseVector* accumulator_vector) const;

  // Applies the index permutation to all entries: index = index_perm[index];
  void ApplyIndexPermutation(const IndexPermutation& index_perm);

  // Same as ApplyIndexPermutation but deletes the index if index_perm[index]
  // is negative.
  void ApplyPartialIndexPermutation(const IndexPermutation& index_perm);

  // Removes the entries for which index_perm[index] is non-negative and appends
  // them to output. Note that the index of the entries are NOT permuted.
  void MoveTaggedEntriesTo(const IndexPermutation& index_perm,
                           SparseVector* output);

  // Returns the coefficient at position index.
  // Call with care: runs in O(number-of-entries) as entries may not be sorted.
  Fractional LookUpCoefficient(Index index) const;

  // Note this method can only be used when the vector has no duplicates.
  EntryIndex num_entries() const {
    DCHECK(CheckNoDuplicates());
    return EntryIndex(num_entries_);
  }

  // Returns the first entry's index and coefficient; note that 'first' doesn't
  // mean 'entry with the smallest index'.
  // Runs in O(1).
  // Note this method can only be used when the vector has no duplicates.
  Index GetFirstIndex() const {
    DCHECK(CheckNoDuplicates());
    return GetIndex(EntryIndex(0));
  }
  Fractional GetFirstCoefficient() const {
    DCHECK(CheckNoDuplicates());
    return GetCoefficient(EntryIndex(0));
  }

  // Like GetFirst*, but for the last entry.
  Index GetLastIndex() const {
    DCHECK(CheckNoDuplicates());
    return GetIndex(num_entries() - 1);
  }
  Fractional GetLastCoefficient() const {
    DCHECK(CheckNoDuplicates());
    return GetCoefficient(num_entries() - 1);
  }

  // Allows to loop over the entry indices like this:
  //   for (const EntryIndex i : sparse_vector.AllEntryIndices()) { ... }
  // TODO(user): consider removing this, in favor of the natural range
  // iteration.
  ::util::IntegerRange<EntryIndex> AllEntryIndices() const {
    return ::util::IntegerRange<EntryIndex>(EntryIndex(0), num_entries_);
  }

  // Returns true if this vector is exactly equal to the given one, i.e. all its
  // index indices and coefficients appear in the same order and are equal.
  bool IsEqualTo(const SparseVector& other) const;

  // An exhaustive, pretty-printed listing of the entries, in their
  // internal order. a.DebugString() == b.DebugString() iff a.IsEqualTo(b).
  std::string DebugString() const;

 protected:
  // Adds a new entry to the sparse vector, growing the internal buffer if
  // needed. It does not set may_contain_duplicates_ to true.
  void AddEntry(Index index, Fractional value) {
    DCHECK_GE(index, 0);
    // Grow the internal storage if there is no space left for the new entry. We
    // increase the size to max(4, 1.5*current capacity).
    if (num_entries_ == capacity_) {
      // Reserve(capacity_ == 0 ? EntryIndex(4)
      //                        : EntryIndex(2 * capacity_.value()));
      Reserve(capacity_ == 0 ? EntryIndex(4)
                             : EntryIndex(2 * capacity_.value()));
      DCHECK_LT(num_entries_, capacity_);
    }
    const EntryIndex new_entry_index = num_entries_;
    ++num_entries_;
    MutableIndex(new_entry_index) = index;
    MutableCoefficient(new_entry_index) = value;
  }

  // Resizes the sparse vector to a smaller size, without re-allocating the
  // internal storage.
  void ResizeDown(EntryIndex new_size) {
    DCHECK_GE(new_size, 0);
    DCHECK_LE(new_size, num_entries_);
    num_entries_ = new_size;
  }

  // Read-only access to the indices and coefficients of the entries of the
  // sparse vector.
  Index GetIndex(EntryIndex i) const {
    DCHECK_GE(i, 0);
    DCHECK_LT(i, num_entries_);
    return index_[i.value()];
  }
  Fractional GetCoefficient(EntryIndex i) const {
    DCHECK_GE(i, 0);
    DCHECK_LT(i, num_entries_);
    return coefficient_[i.value()];
  }

  // Mutable access to the indices and coefficients of the entries of the sparse
  // vector.
  Index& MutableIndex(EntryIndex i) {
    DCHECK_GE(i, 0);
    DCHECK_LT(i, num_entries_);
    return index_[i.value()];
  }
  Fractional& MutableCoefficient(EntryIndex i) {
    DCHECK_GE(i, 0);
    DCHECK_LT(i, num_entries_);
    return coefficient_[i.value()];
  }

  // The internal storage of the sparse vector. Both the indices and the
  // coefficients are stored in the same buffer; the first
  // sizeof(Index)*capacity_ bytes are used for storing the indices, the
  // following sizeof(Fractional)*capacity_ bytes contain the values. This
  // representation ensures that for small vectors, both the indices and the
  // coefficients are in the same page/cache line.
  // We use a single buffer for both arrays. The amount of data copied during
  // relocations is the same in both cases, and it is much smaller than the cost
  // of an additional allocation - especially when the vectors are small.
  // Moreover, using two separate vectors/buffers would mean that even small
  // vectors would be spread across at least two different cache lines.
  std::unique_ptr<char[]> buffer_;
  EntryIndex num_entries_;
  EntryIndex capacity_;

  // Pointers to the first elements of the index and coefficient arrays.
  Index* index_ = nullptr;
  Fractional* coefficient_ = nullptr;

  // This is here to speed up the CheckNoDuplicates() methods and is mutable
  // so we can perform checks on const argument.
  mutable bool may_contain_duplicates_;

 private:
  // Actual implementation of AddMultipleToSparseVectorAndDeleteCommonIndex()
  // and AddMultipleToSparseVectorAndIgnoreCommonIndex() which is shared.
  void AddMultipleToSparseVectorInternal(
      bool delete_common_index, Fractional multiplier, Index common_index,
      Fractional drop_tolerance, SparseVector* accumulator_vector) const;
};

// --------------------------------------------------------
// SparseVectorEntry
// --------------------------------------------------------

// A reference-like class that points to a certain element of a sparse data
// structure that stores its elements in two parallel arrays. The main purpose
// of the entry class is to support implementation of iterator objects over the
// sparse data structure.
// Note that the entry object does not own the data, and it is valid only as
// long as the underlying sparse data structure; it may also be invalidated if
// the underlying sparse data structure is modified.
template <typename IndexType>
class SparseVectorEntry {
 public:
  using Index = IndexType;

  Index index() const { return index_[i_.value()]; }
  Fractional coefficient() const { return coefficient_[i_.value()]; }

 protected:
  // Creates the sparse vector entry from the given base pointers and the index.
  // We accept the low-level data structures rather than a SparseVector
  // reference to make it possible to use the SparseVectorEntry and
  // SparseVectorIterator classes also for other data structures using the same
  // internal data representation.
  // Note that the constructor is intentionally made protected, so that the
  // entry can be created only as a part of the construction of an iterator over
  // a sparse data structure.
  SparseVectorEntry(const Index* indices, const Fractional* coefficients,
                    EntryIndex i)
      : i_(i), index_(indices), coefficient_(coefficients) {}

  // The index of the sparse vector entry represented by this object.
  EntryIndex i_;
  // The index and coefficient arrays of the sparse vector.
  // NOTE(user): Keeping directly the index and the base pointers gives the
  // best performance with a tiny margin of the options:
  // 1. keep the base pointers and an index of the current entry,
  // 2. keep pointers to the current index and the current coefficient and
  //    increment both when moving the iterator.
  // 3. keep a pointer to the sparse vector object and the index of the current
  //    entry.
  const Index* index_;
  const Fractional* coefficient_;
};

template <typename IndexType, typename IteratorType>
IteratorType SparseVector<IndexType, IteratorType>::begin() const {
  return Iterator(this->index_, this->coefficient_, EntryIndex(0));
}

template <typename IndexType, typename IteratorType>
IteratorType SparseVector<IndexType, IteratorType>::end() const {
  return Iterator(this->index_, this->coefficient_, num_entries_);
}

// --------------------------------------------------------
// SparseVector implementation
// --------------------------------------------------------
template <typename IndexType, typename IteratorType>
SparseVector<IndexType, IteratorType>::SparseVector()
    : num_entries_(0),
      capacity_(0),
      index_(nullptr),
      coefficient_(nullptr),
      may_contain_duplicates_(false) {}

template <typename IndexType, typename IteratorType>
SparseVector<IndexType, IteratorType>::SparseVector(const SparseVector& other) {
  PopulateFromSparseVector(other);
}

template <typename IndexType, typename IteratorType>
SparseVector<IndexType, IteratorType>&
SparseVector<IndexType, IteratorType>::operator=(const SparseVector& other) {
  PopulateFromSparseVector(other);
  return *this;
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::Clear() {
  num_entries_ = EntryIndex(0);
  may_contain_duplicates_ = false;
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::ClearAndRelease() {
  capacity_ = EntryIndex(0);
  num_entries_ = EntryIndex(0);
  index_ = nullptr;
  coefficient_ = nullptr;
  buffer_.reset();
  may_contain_duplicates_ = false;
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::Reserve(EntryIndex new_capacity) {
  if (new_capacity <= capacity_) return;
  // Round up the capacity to a multiple of four. This way, the start of the
  // coefficient array will be aligned to 16-bytes, provided that the buffer
  // used for storing the data is aligned in that way.
  if (new_capacity.value() & 3) {
    new_capacity += EntryIndex(4 - (new_capacity.value() & 3));
  }

  const size_t index_buffer_size = new_capacity.value() * sizeof(Index);
  const size_t value_buffer_size = new_capacity.value() * sizeof(Fractional);
  const size_t new_buffer_size = index_buffer_size + value_buffer_size;
  std::unique_ptr<char[]> new_buffer(new char[new_buffer_size]);
  IndexType* const new_index = reinterpret_cast<Index*>(new_buffer.get());
  Fractional* const new_coefficient =
      reinterpret_cast<Fractional*>(new_index + new_capacity.value());

  // Avoid copying the data if the vector is empty.
  if (num_entries_ > 0) {
    // NOTE(user): We use memmove instead of std::copy, because the latter
    // leads to naive copying code when used with strong ints (a loop that
    // copies a single 32-bit value in each iteration), and as of 06/2016,
    // memmove is 3-4x faster on Haswell.
    std::memmove(new_index, index_, sizeof(IndexType) * num_entries_.value());
    std::memmove(new_coefficient, coefficient_,
                 sizeof(Fractional) * num_entries_.value());
  }
  std::swap(buffer_, new_buffer);
  index_ = new_index;
  coefficient_ = new_coefficient;
  capacity_ = new_capacity;
}

template <typename IndexType, typename IteratorType>
bool SparseVector<IndexType, IteratorType>::IsEmpty() const {
  return num_entries_ == EntryIndex(0);
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::Swap(SparseVector* other) {
  std::swap(buffer_, other->buffer_);
  std::swap(num_entries_, other->num_entries_);
  std::swap(capacity_, other->capacity_);
  std::swap(may_contain_duplicates_, other->may_contain_duplicates_);
  std::swap(index_, other->index_);
  std::swap(coefficient_, other->coefficient_);
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::CleanUp() {
  // TODO(user): Implement in-place sorting of the entries and cleanup. The
  // current version converts the data to an array-of-pairs representation that
  // can be sorted easily with std::stable_sort, and the converts the sorted
  // data back to the struct-of-arrays implementation.
  // The current version is ~20% slower than the in-place sort on the
  // array-of-struct representation. It is not visible on GLOP benchmarks, but
  // it increases peak memory usage by ~8%.
  // Implementing in-place search will require either implementing a custom
  // sorting code, or custom iterators that abstract away the internal
  // representation.
  std::vector<std::pair<Index, Fractional>> entries;
  entries.reserve(num_entries_.value());
  for (EntryIndex i(0); i < num_entries_; ++i) {
    entries.emplace_back(GetIndex(i), GetCoefficient(i));
  }
  std::stable_sort(
      entries.begin(), entries.end(),
      [](const std::pair<Index, Fractional>& a,
         const std::pair<Index, Fractional>& b) { return a.first < b.first; });

  EntryIndex new_size(0);
  for (int i = 0; i < num_entries_; ++i) {
    const std::pair<Index, Fractional> entry = entries[i];
    if (entry.second == 0.0) continue;
    if (i + 1 == num_entries_ || entry.first != entries[i + 1].first) {
      MutableIndex(new_size) = entry.first;
      MutableCoefficient(new_size) = entry.second;
      ++new_size;
    }
  }
  ResizeDown(new_size);
  may_contain_duplicates_ = false;
}

template <typename IndexType, typename IteratorType>
bool SparseVector<IndexType, IteratorType>::IsCleanedUp() const {
  Index previous_index(-1);
  for (const EntryIndex i : AllEntryIndices()) {
    const Index index = GetIndex(i);
    if (index <= previous_index || GetCoefficient(i) == 0.0) return false;
    previous_index = index;
  }
  may_contain_duplicates_ = false;
  return true;
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::PopulateFromSparseVector(
    const SparseVector& sparse_vector) {
  // Clear the sparse vector before reserving the new capacity. If we didn't do
  // this, Reserve would have to copy the current contents of the vector if it
  // allocated a new buffer. This would be wasteful, since we overwrite it in
  // the next step anyway.
  Clear();
  Reserve(sparse_vector.capacity_);
  // If there are no entries, then sparse_vector.index_ or .coefficient_
  // may be nullptr or invalid, and accessing them in memmove is UB,
  // even if the moved size is zero.
  if (sparse_vector.num_entries_ > 0) {
    // NOTE(user): Using a single memmove would be slightly faster, but it
    // would not work correctly if this already had a greater capacity than
    // sparse_vector, because the coefficient_ pointer would be positioned
    // incorrectly.
    std::memmove(index_, sparse_vector.index_,
                 sizeof(Index) * sparse_vector.num_entries_.value());
    std::memmove(coefficient_, sparse_vector.coefficient_,
                 sizeof(Fractional) * sparse_vector.num_entries_.value());
  }
  num_entries_ = sparse_vector.num_entries_;
  may_contain_duplicates_ = sparse_vector.may_contain_duplicates_;
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::PopulateFromDenseVector(
    const DenseVector& dense_vector) {
  Clear();
  const Index num_indices(dense_vector.size());
  for (Index index(0); index < num_indices; ++index) {
    if (dense_vector[index] != 0.0) {
      SetCoefficient(index, dense_vector[index]);
    }
  }
  may_contain_duplicates_ = false;
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::AppendEntriesWithOffset(
    const SparseVector& sparse_vector, Index offset) {
  for (const EntryIndex i : sparse_vector.AllEntryIndices()) {
    const Index new_index = offset + sparse_vector.GetIndex(i);
    DCHECK_GE(new_index, 0);
    AddEntry(new_index, sparse_vector.GetCoefficient(i));
  }
  may_contain_duplicates_ = true;
}

template <typename IndexType, typename IteratorType>
bool SparseVector<IndexType, IteratorType>::CheckNoDuplicates(
    StrictITIVector<IndexType, bool>* boolean_vector) const {
  RETURN_VALUE_IF_NULL(boolean_vector, false);
  // Note(user): Using num_entries() or any function that call
  // CheckNoDuplicates() again will cause an infinite loop!
  if (!may_contain_duplicates_ || num_entries_ <= 1) return true;

  // Update size if needed.
  const Index max_index =
      *std::max_element(index_, index_ + num_entries_.value());
  if (boolean_vector->size() <= max_index) {
    boolean_vector->resize(max_index + 1, false);
  }

  may_contain_duplicates_ = false;
  for (const EntryIndex i : AllEntryIndices()) {
    const Index index = GetIndex(i);
    if ((*boolean_vector)[index]) {
      may_contain_duplicates_ = true;
      break;
    }
    (*boolean_vector)[index] = true;
  }

  // Reset boolean_vector to false.
  for (const EntryIndex i : AllEntryIndices()) {
    (*boolean_vector)[GetIndex(i)] = false;
  }
  return !may_contain_duplicates_;
}

template <typename IndexType, typename IteratorType>
bool SparseVector<IndexType, IteratorType>::CheckNoDuplicates() const {
  // Using num_entries() or any function in that will call CheckNoDuplicates()
  // again will cause an infinite loop!
  if (!may_contain_duplicates_ || num_entries_ <= 1) return true;
  StrictITIVector<Index, bool> boolean_vector;
  return CheckNoDuplicates(&boolean_vector);
}

// Do not filter out zero values, as a zero value can be added to reset a
// previous value. Zero values and duplicates will be removed by CleanUp.
template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::SetCoefficient(Index index,
                                                           Fractional value) {
  AddEntry(index, value);
  may_contain_duplicates_ = true;
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::DeleteEntry(Index index) {
  DCHECK(CheckNoDuplicates());
  EntryIndex i(0);
  const EntryIndex end(num_entries());
  while (i < end && GetIndex(i) != index) {
    ++i;
  }
  if (i == end) return;
  const int num_moved_entries = (num_entries_ - i).value() - 1;
  std::memmove(index_ + i.value(), index_ + i.value() + 1,
               sizeof(Index) * num_moved_entries);
  std::memmove(coefficient_ + i.value(), coefficient_ + i.value() + 1,
               sizeof(Fractional) * num_moved_entries);
  --num_entries_;
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::RemoveNearZeroEntries(
    Fractional threshold) {
  DCHECK(CheckNoDuplicates());
  EntryIndex new_index(0);
  for (const EntryIndex i : AllEntryIndices()) {
    const Fractional magnitude = fabs(GetCoefficient(i));
    if (magnitude > threshold) {
      MutableIndex(new_index) = GetIndex(i);
      MutableCoefficient(new_index) = GetCoefficient(i);
      ++new_index;
    }
  }
  ResizeDown(new_index);
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::RemoveNearZeroEntriesWithWeights(
    Fractional threshold, const DenseVector& weights) {
  DCHECK(CheckNoDuplicates());
  EntryIndex new_index(0);
  for (const EntryIndex i : AllEntryIndices()) {
    if (fabs(GetCoefficient(i)) * weights[GetIndex(i)] > threshold) {
      MutableIndex(new_index) = GetIndex(i);
      MutableCoefficient(new_index) = GetCoefficient(i);
      ++new_index;
    }
  }
  ResizeDown(new_index);
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::MoveEntryToFirstPosition(
    Index index) {
  DCHECK(CheckNoDuplicates());
  for (const EntryIndex i : AllEntryIndices()) {
    if (GetIndex(i) == index) {
      std::swap(MutableIndex(EntryIndex(0)), MutableIndex(i));
      std::swap(MutableCoefficient(EntryIndex(0)), MutableCoefficient(i));
      return;
    }
  }
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::MoveEntryToLastPosition(
    Index index) {
  DCHECK(CheckNoDuplicates());
  const EntryIndex last_entry = num_entries() - 1;
  for (const EntryIndex i : AllEntryIndices()) {
    if (GetIndex(i) == index) {
      std::swap(MutableIndex(last_entry), MutableIndex(i));
      std::swap(MutableCoefficient(last_entry), MutableCoefficient(i));
      return;
    }
  }
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::MultiplyByConstant(
    Fractional factor) {
  for (const EntryIndex i : AllEntryIndices()) {
    MutableCoefficient(i) *= factor;
  }
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::ComponentWiseMultiply(
    const DenseVector& factors) {
  for (const EntryIndex i : AllEntryIndices()) {
    MutableCoefficient(i) *= factors[GetIndex(i)];
  }
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::DivideByConstant(
    Fractional factor) {
  for (const EntryIndex i : AllEntryIndices()) {
    MutableCoefficient(i) /= factor;
  }
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::ComponentWiseDivide(
    const DenseVector& factors) {
  for (const EntryIndex i : AllEntryIndices()) {
    MutableCoefficient(i) /= factors[GetIndex(i)];
  }
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::CopyToDenseVector(
    Index num_indices, DenseVector* dense_vector) const {
  RETURN_IF_NULL(dense_vector);
  dense_vector->AssignToZero(num_indices);
  for (const EntryIndex i : AllEntryIndices()) {
    (*dense_vector)[GetIndex(i)] = GetCoefficient(i);
  }
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::PermutedCopyToDenseVector(
    const IndexPermutation& index_perm, Index num_indices,
    DenseVector* dense_vector) const {
  RETURN_IF_NULL(dense_vector);
  dense_vector->AssignToZero(num_indices);
  for (const EntryIndex i : AllEntryIndices()) {
    (*dense_vector)[index_perm[GetIndex(i)]] = GetCoefficient(i);
  }
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::AddMultipleToDenseVector(
    Fractional multiplier, DenseVector* dense_vector) const {
  RETURN_IF_NULL(dense_vector);
  if (multiplier == 0.0) return;
  for (const EntryIndex i : AllEntryIndices()) {
    (*dense_vector)[GetIndex(i)] += multiplier * GetCoefficient(i);
  }
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::
    AddMultipleToSparseVectorAndDeleteCommonIndex(
        Fractional multiplier, Index removed_common_index,
        Fractional drop_tolerance, SparseVector* accumulator_vector) const {
  AddMultipleToSparseVectorInternal(true, multiplier, removed_common_index,
                                    drop_tolerance, accumulator_vector);
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::
    AddMultipleToSparseVectorAndIgnoreCommonIndex(
        Fractional multiplier, Index removed_common_index,
        Fractional drop_tolerance, SparseVector* accumulator_vector) const {
  AddMultipleToSparseVectorInternal(false, multiplier, removed_common_index,
                                    drop_tolerance, accumulator_vector);
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::AddMultipleToSparseVectorInternal(
    bool delete_common_index, Fractional multiplier, Index common_index,
    Fractional drop_tolerance, SparseVector* accumulator_vector) const {
  // DCHECK that the input is correct.
  DCHECK(IsCleanedUp());
  DCHECK(accumulator_vector->IsCleanedUp());
  DCHECK(CheckNoDuplicates());
  DCHECK(accumulator_vector->CheckNoDuplicates());
  DCHECK_NE(0.0, LookUpCoefficient(common_index));
  DCHECK_NE(0.0, accumulator_vector->LookUpCoefficient(common_index));

  // Implementation notes: we create a temporary SparseVector "c" to hold the
  // result. We call "a" the first vector (i.e. the current object, which will
  // be multiplied by "multiplier"), and "b" the second vector (which will be
  // swapped with "c" at the end to hold the result).
  // We incrementally build c as: a * multiplier + b.
  const SparseVector& a = *this;
  const SparseVector& b = *accumulator_vector;
  SparseVector c;
  EntryIndex ia(0);  // Index in the vector "a"
  EntryIndex ib(0);  // ... and "b"
  EntryIndex ic(0);  // ... and "c"
  const EntryIndex size_a = a.num_entries();
  const EntryIndex size_b = b.num_entries();
  const int size_adjustment = delete_common_index ? -2 : 0;
  const EntryIndex new_size_upper_bound = size_a + size_b + size_adjustment;
  c.Reserve(new_size_upper_bound);
  c.num_entries_ = new_size_upper_bound;
  while ((ia < size_a) && (ib < size_b)) {
    const Index index_a = a.GetIndex(ia);
    const Index index_b = b.GetIndex(ib);
    // Benchmarks done by fdid@ in 2012 showed that it was faster to put the
    // "if" clauses in that specific order.
    if (index_a == index_b) {
      if (index_a != common_index) {
        const Fractional a_coeff_mul = multiplier * a.GetCoefficient(ia);
        const Fractional b_coeff = b.GetCoefficient(ib);
        const Fractional sum = a_coeff_mul + b_coeff;

        // We do not want to leave near-zero entries.
        // TODO(user): expose the tolerance used here.
        if (std::abs(sum) > drop_tolerance) {
          c.MutableIndex(ic) = index_a;
          c.MutableCoefficient(ic) = sum;
          ++ic;
        }
      } else if (!delete_common_index) {
        c.MutableIndex(ic) = b.GetIndex(ib);
        c.MutableCoefficient(ic) = b.GetCoefficient(ib);
        ++ic;
      }
      ++ia;
      ++ib;
    } else if (index_a < index_b) {
      const Fractional new_value = multiplier * a.GetCoefficient(ia);
      if (std::abs(new_value) > drop_tolerance) {
        c.MutableIndex(ic) = index_a;
        c.MutableCoefficient(ic) = new_value;
        ++ic;
      }
      ++ia;
    } else {  // index_b < index_a
      c.MutableIndex(ic) = b.GetIndex(ib);
      c.MutableCoefficient(ic) = b.GetCoefficient(ib);
      ++ib;
      ++ic;
    }
  }
  while (ia < size_a) {
    const Fractional new_value = multiplier * a.GetCoefficient(ia);
    if (std::abs(new_value) > drop_tolerance) {
      c.MutableIndex(ic) = a.GetIndex(ia);
      c.MutableCoefficient(ic) = new_value;
      ++ic;
    }
    ++ia;
  }
  while (ib < size_b) {
    c.MutableIndex(ic) = b.GetIndex(ib);
    c.MutableCoefficient(ic) = b.GetCoefficient(ib);
    ++ib;
    ++ic;
  }
  c.ResizeDown(ic);
  c.may_contain_duplicates_ = false;
  c.Swap(accumulator_vector);
  DCHECK(accumulator_vector->IsCleanedUp());
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::ApplyIndexPermutation(
    const IndexPermutation& index_perm) {
  for (const EntryIndex i : AllEntryIndices()) {
    MutableIndex(i) = index_perm[GetIndex(i)];
  }
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::ApplyPartialIndexPermutation(
    const IndexPermutation& index_perm) {
  EntryIndex new_index(0);
  for (const EntryIndex i : AllEntryIndices()) {
    const Index index = GetIndex(i);
    if (index_perm[index] >= 0) {
      MutableIndex(new_index) = index_perm[index];
      MutableCoefficient(new_index) = GetCoefficient(i);
      ++new_index;
    }
  }
  ResizeDown(new_index);
}

template <typename IndexType, typename IteratorType>
void SparseVector<IndexType, IteratorType>::MoveTaggedEntriesTo(
    const IndexPermutation& index_perm, SparseVector* output) {
  // Note that this function is called many times, so performance does matter
  // and it is why we optimized the "nothing to do" case.
  const EntryIndex end(num_entries_);
  EntryIndex i(0);
  while (true) {
    if (i >= end) return;  // "nothing to do" case.
    if (index_perm[GetIndex(i)] >= 0) break;
    ++i;
  }
  output->AddEntry(GetIndex(i), GetCoefficient(i));
  for (EntryIndex j(i + 1); j < end; ++j) {
    if (index_perm[GetIndex(j)] < 0) {
      MutableIndex(i) = GetIndex(j);
      MutableCoefficient(i) = GetCoefficient(j);
      ++i;
    } else {
      output->AddEntry(GetIndex(j), GetCoefficient(j));
    }
  }
  ResizeDown(i);

  // TODO(user): In the way we use this function, we know that will not
  // happen, but it is better to be careful so we can check that properly in
  // debug mode.
  output->may_contain_duplicates_ = true;
}

template <typename IndexType, typename IteratorType>
Fractional SparseVector<IndexType, IteratorType>::LookUpCoefficient(
    Index index) const {
  Fractional value(0.0);
  for (const EntryIndex i : AllEntryIndices()) {
    if (GetIndex(i) == index) {
      // Keep in mind the vector may contains several entries with the same
      // index. In such a case the last one is returned.
      // TODO(user): investigate whether an optimized version of
      // LookUpCoefficient for "clean" columns yields speed-ups.
      value = GetCoefficient(i);
    }
  }
  return value;
}

template <typename IndexType, typename IteratorType>
bool SparseVector<IndexType, IteratorType>::IsEqualTo(
    const SparseVector& other) const {
  // We do not take into account the mutable value may_contain_duplicates_.
  if (num_entries() != other.num_entries()) return false;
  for (const EntryIndex i : AllEntryIndices()) {
    if (GetIndex(i) != other.GetIndex(i)) return false;
    if (GetCoefficient(i) != other.GetCoefficient(i)) return false;
  }
  return true;
}

template <typename IndexType, typename IteratorType>
std::string SparseVector<IndexType, IteratorType>::DebugString() const {
  std::string s;
  for (const EntryIndex i : AllEntryIndices()) {
    if (i != 0) s += ", ";
    absl::StrAppendFormat(&s, "[%d]=%g", GetIndex(i).value(),
                          GetCoefficient(i));
  }
  return s;
}

}  // namespace glop
}  // namespace operations_research

#endif  // OR_TOOLS_LP_DATA_SPARSE_VECTOR_H_
